import { exec, execSync } from 'child_process'
import { ClientErrorExtensions, SFTPWrapper, Client } from 'ssh2'
import type { ClientChannel } from "ssh2";
import fs from "fs";
// 部署相关
import * as _conf from "./config/ssh.json";
import * as _package from "./package.json";

// 服务器部署内容
interface SSHConnectConf {
    host: string,  //主机ip
    port: number,                //SSH 连接端口
    username: string,        //用户名
    password: string,     //用户登录密码
}

// 连接服务器
class AutoDeployer {
    private connect: Client | null = null;

    // 远端服务器根目录地址
    private remoteRootPath: string = ""
    // 远端服务器项目完整根目录地址
    private fullAppRootPath: string = "";
    // 远端上传打压缩包文件地址
    private remoteCompressPackagePath: string = "";
    // 远端备份项目地址
    private remoteBackPath: string = "";
    // 备份文件夹根目录
    private remoteBackRootPath: string = ""
    // 远端静态资源根目录
    private remoteAppStaticRoot: string = ""

    constructor() {
        const me = this;
        const { name, version } = _package;
        const { projectPubRoot, projectBackDir, projectDir, remoteRootPath } = _conf;
        let time = me.createDeployTime();
        me.remoteRootPath = `${remoteRootPath}`; //跳转到所有项目部署的根目录
        // 服务压缩包
        me.remoteCompressPackagePath = `${me.remoteRootPath}/dist.tar.gz`;
        // 生成完整的远端项目地址  frontend/
        me.fullAppRootPath = `${projectPubRoot}`
        // 备份文件夹根目录
        me.remoteBackRootPath = `${remoteRootPath}/${projectBackDir}`;
        // 生成备份文件包路径
        me.remoteBackPath = `${me.remoteBackRootPath}/${name}/v_${version}_${time}/`
        console.log(me, '???')
    }

    // 连接服务器
    connectSSH(serverConfig: SSHConnectConf) {
        var me = this;
        console.log(me.remoteRootPath, '-----开始连接远端服务器');
        me.connect = new Client();
        me.connect.on('ready', () => {
            console.log(me.remoteRootPath, '-----远端服务器连接就绪')
            me.uploadPackageFile(me);
        }).on('error', function (e: ClientErrorExtensions) {
            me.connectFailedCb(e);
        }).connect(serverConfig);
    }

    // connect error event
    connectFailedCb(context: ClientErrorExtensions) {
        console.log('ssh操作失败失败!', context)
    }

    // when connect 
    uploadPackageFile(context: AutoDeployer) {
        console.log(context.remoteCompressPackagePath, '-----打包文件上传开始!')
        context.connect && context.connect.sftp((err: Error | undefined, sftp: SFTPWrapper) => {
            if (err) {
                console.log("获取上传信息失败!")
                return
            }
            console.log('远端地址', context.fullAppRootPath);
            sftp.fastPut('./dist.tar.gz', `${context.remoteCompressPackagePath}`, {}, () => {
                console.log(context.remoteCompressPackagePath, '-----打包文件上传成功!');
                // const all = context.fullAppRootPath + '/*';
                let cmd = `
                cd ${context.remoteRootPath}
                mkdir -p ${context.remoteBackRootPath} ${context.fullAppRootPath} ${context.remoteBackPath}
                mv ${context.fullAppRootPath}/exe/* -f ${context.remoteBackPath}
                mv ${context.fullAppRootPath}/mac/* -f ${context.remoteBackPath}
                mv ${context.fullAppRootPath}/js/* -f ${context.remoteBackPath}

                tar zxvf dist.tar.gz
                mv zip/* -f ${context.fullAppRootPath}
                rm -rf dist.tar.gz zip
                exit 
                `;
                // 相关执行步骤如下:
                // * cd 到 linux操作系统根目录
                // * 创建备份文件夹
                // * 备份项目文件
                // * 解压打包文件
                // * 解压后文件命名移动到指定项目文件夹
                // * 清除空余的文件夹
                // * 退出命令

                context.handleLinuxShell(cmd, context);
            })
        })
    }

    // handle shell
    handleLinuxShell(cmdCode: string, context: AutoDeployer) {
        console.log(`======> ${_package.name} 服务器环境部署开始`);
        // open remote server device shell
        context.connect && context.connect.shell(function (err: Error | undefined, stream: ClientChannel) {
            if (err !== undefined) {
                console.log('remoteShell------操作失败')
                return;
            }
            stream.on('error', function (e: any) {
                console.log('remoteShell------操作失败', e)
            }).on('data', function (data: Buffer) {
                let message = data.toString();
                console.log(message,'from remote!')
                if (message.indexOf('pnpm i') !== -1) {
                    if (message.indexOf('exit') !== -1) return;
                    console.log(`======> ${_package.name} 项目依赖开始下载中...`);
                    console.log('tips: =====> 首次依赖安装时间较久,请耐心等待.....')
                } else if (message.indexOf('Done in') !== -1) {
                    console.log(`======> ${_package.name} 项目依赖下载完成!`);
                    context.updateConfiguration();
                } else if (message.indexOf('Done.') !== -1) {
                    console.log(`======> ${_package.name} 项目部署成功!`, `${_conf.host}:${context.getAppPort()} 可访问`);
                    context.updateConfiguration();
                }
                else {
                    // console.log(message)
                }
            }).on('close', function () {
                context.connect && context.connect.end();
                console.log(context.remoteRootPath, '-----ssh连接已断开');
                console.log('请在该网址上下载:',);
                console.timeEnd('auto-deploy')
            }).stderr.on('data', function (data: any) {
                console.log('stderr: ' + data)
            })
            stream.end(cmdCode)
        })
    }

    // 
    createDeployTime() {
        let dt = new Date();
        let y = dt.getFullYear(),
            m = (dt.getMonth() + 1 + "").padStart(2, "0"),
            d = (dt.getDate() + "").padStart(2, "0"),
            hh = (dt.getHours() + "").padStart(2, "0"),
            mm = (dt.getMinutes() + "").padStart(2, "0"),
            ss = (dt.getSeconds() + "").padStart(2, "0");
        return `${y}-${m}-${d}_${hh}:${mm}:${ss}`
    }

    updateConfiguration() {
        let content = { ..._conf };
        content.installed = true;
        // content.serverIds = "";
        fs.writeFileSync("./config/ssh.json", JSON.stringify(content), "utf-8")
        console.log('config/ssh.json', "-----文件已更新")
        console.log(this.remoteRootPath, '-----自动化部署完成!')
    }

    getAppPort(): number {
        const data: string[] = fs.readFileSync('.env.production').toString()?.split('\n');
        const portRow = data.find(item => item.indexOf('APP_PORT') !== -1);
        return portRow === undefined ? 3000 : (parseInt(portRow.replace(/\D/g, '')) || 3000);
    }
}

console.time('auto-deploy')
console.log('开始前准备------文件包开始压缩!')
// let pro = exec('pnpm run build:win', () => { })
// pro?.stdout?.pipe(process.stdout);
// pro.on('exit', () => {

execSync("pub_win.sh");
console.log('开始前准备------文件包压缩完成!');



// console.timeEnd('auto-deploy')
new AutoDeployer().connectSSH({
    host: _conf.host,
    username: _conf.username,
    port: _conf.port,
    password: _conf.password
});
// })